﻿using PaperMaster.Chess;
using PaperMaster.Chess.PieceSpace;
using PaperMaster.Model;
using PaperMaster.Utilities;
using PaperMaster.Chess.ChessModel;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEngine;
using PaperMaster.Utility;
using PaperMaster.Chess.PlayerCore;
using PaperMaster.Info;

namespace PaperMaster.Chess.CardSpace
{
    public enum Card
    {
        Sample
    }
    /// <summary>
    /// 一张牌的控制器
    /// </summary>
    public abstract class CardControllerBase
    {
        CardModelBase _model;
        /// <summary>
        /// 该牌的模型
        /// </summary>
        public virtual CardModelBase model
        {
            get
            {
                return _model;
            }
            set
            {
                _model = value;
            }
        }
        public CardControllerBase()
        {

        }
        /// <summary>
        /// 根据指定的model创建一个控制器
        /// </summary>
        /// <param name="model"></param>
        public CardControllerBase(CardModelBase model)
        {
            SetModel(model);
        }
        public virtual void SetModel(CardModelBase model)
        {
            this.model.cardType = model.cardType;
            this.model.elementType = model.elementType;
            this.model.manaCost = model.manaCost;
        }
        public virtual void SetModel(AbstractCardModelBase model)
        {
            this.model.cardType = model.cardType;
            this.model.elementType = model.elementType;
            this.model.manaCost = model.manaCost;
        }
        /// <summary>
        /// 根据自己的模型，新建一个模型。
        /// </summary>
        /// <param name="model"></param>
        public virtual CardModelBase CopyModel()
        {
            CardModelBase nModel = new CardModelBase(this.model);
            return nModel;
        }
        public void SetViewController(CardViewController viewController)
        {
            model.viewController = viewController;
        }
        /// <summary>
        /// 抽入手牌时触发
        /// </summary>
        public virtual void DrawIn()
        {

        }
        /// <summary>
        /// 打出这张牌,若成功打出则返回true，否则返回false
        /// </summary>
        public virtual bool Play()
        {
            if (!CanPlay())
            {
                PreConditionInfo();
                return false;
            }
            UseMana();
            return true;
        }
        /// <summary>
        /// 消耗掉牌对应的法力值
        /// </summary>
        protected virtual void UseMana()
        {
            model.playerModel.mana -= model.manaCost;
        }
        /// <summary>
        /// 洗入弃牌堆时触发
        /// </summary>
        public virtual void WashedAway()
        {

        }
        /// <summary>
        /// 牌被选中时触发
        /// </summary>
        public virtual void OnSelect()
        {
            if (!CanPlay())
            {
                PreConditionInfo();
            }
        }
        /// <summary>
        /// 牌能否打出
        /// </summary>
        public virtual bool CanPlay()
        {
            if (model.playerModel.mana < model.manaCost)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 不能打出牌时，显示提示信息
        /// </summary>
        protected virtual void PreConditionInfo()
        {
            Debug.Log(model._preCondition);
        }

    }
    /// <summary>
    /// 一张牌的模型
    /// </summary>
    public class AbstractCardModelBase
    {
        /// <summary>
        /// 卡牌名
        /// </summary>
        public Card cardType;
        /// <summary>
        /// 卡牌元素
        /// </summary>
        public ElementType elementType;
        protected string _description;
        /// <summary>
        /// 卡牌描述。该描述仅仅为基本描述，可以重写
        /// </summary>
        public virtual string description{
            get
            {
                return _description;
            }
            set
            {
                _description = value;
            }
        }

        protected int _manaCost;
        /// <summary>
        /// 法力消耗
        /// </summary>
        public virtual int manaCost { 
            get
            {
                return _manaCost; 
            }
            set
            {
                _manaCost = value; 
            } 
        }
        public AbstractCardModelBase()
        {

        }

        public AbstractCardModelBase(Card card,int manaCost)
        {
            this.cardType = card;
            this.manaCost = manaCost;
        }
        /// <summary>
        /// 复制一张数值一样的卡牌
        /// </summary>
        /// <param name="card"></param>
        public AbstractCardModelBase(AbstractCardModelBase card)
        {
            Copy(card);
        }
        /// <summary>
        /// 复制卡牌
        /// </summary>
        public virtual void Copy(AbstractCardModelBase card)
        {
            cardType = card.cardType;
            manaCost = card.manaCost;
            elementType = card.elementType;
            description = card.description;
        }
    }
    /// <summary>
    ///
    /// </summary>
    public interface ISingleCardModel<T>
    {
        void Copy(T model);
    }
    /// <summary>
    /// 非模板的单张卡片
    /// </summary>
    public class CardModelBase : AbstractCardModelBase,ISingleCardModel<CardModelBase>
    {
        /// <summary>
        /// 视图控制器
        /// </summary>
        public CardViewController viewController;
        IChessModel __chessModel;
        ICardModel __cardModel;
        IPlayerCoreModel _playerModel;
        public override int manaCost
        {
            get
            {
                return cardModel.DecorateManaCost(_manaCost, elementType);
            }
            set
            {
                _manaCost = value;
            }
        }

        public IChessModel chessModel
        {
            get
            {
                if (__chessModel == null)
                {
                    __chessModel = ModelContainer.Get<IChessModel>();
                }
                return __chessModel;
            }
        }
        public ICardModel cardModel
        {
            get
            {
                if (__cardModel == null)
                {
                    __cardModel = ModelContainer.Get<ICardModel>();
                }
                return __cardModel;
            }
        }
        public IPlayerCoreModel playerModel
        {
            get
            {
                if (_playerModel == null)
                {
                    _playerModel = ModelContainer.Get<IPlayerCoreModel>();
                }
                return _playerModel;
            }
        }
        /// <summary>
        /// 打出这张牌的前置条件
        /// </summary>
        public virtual string _preCondition
        {
            get
            {
                return "无";
            }
        }
        protected virtual void Init()
        {

        }
        public CardModelBase(Card card)
        {
            Copy(cardModel.GetCardModel(card));
        }
        public CardModelBase(AbstractCardModelBase card)
        {
            Copy(card);
        }
        public void Copy(CardModelBase card)
        {
            base.Copy(card);
        }
    }
    public interface ICardFactory : IFactory<Card, GameObject>
    {
        /// <summary>
        /// 根据model来创建卡牌
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        GameObject Produce(CardModelBase model);
    }
    public class CardFactory : ICardFactory
    {
        /// <summary>
        /// 将采用默认数值生成卡牌
        /// </summary>
        /// <param name="label"></param>
        /// <returns></returns>
        public GameObject Produce(Card label)
        {
            GameObject prefab = Resources.Load<GameObject>(Strings.GetString(StringType.CardPrefabPath) + label.ToString());
            return GameObject.Instantiate(prefab);
        }

        public GameObject Produce(CardModelBase model)
        {
            GameObject prefab = Resources.Load<GameObject>(Strings.GetString(StringType.CardPrefabPath) + model.cardType.ToString());
            GameObject ret = GameObject.Instantiate(prefab);
            ret.GetComponent<CardViewController>().controller.model = model;
            ret.GetComponent<CardViewController>().controller.SetViewController(ret.GetComponent<CardViewController>());
            return ret;
        }
    }
    public class MyListEnum<T> : IEnumerator<T>
    {
        List<T> _items;
        int _position = -1;


        public T Current
        {
            get
            {
                try
                {
                    return _items[_position];
                }
                catch (IndexOutOfRangeException)
                {
                    throw new InvalidOperationException();
                }
            }
        }


        object IEnumerator.Current
        {
            get
            {
                return Current;
            }
        }


        public MyListEnum(List<T> items)
        {
            _items = new List<T>();
            foreach(var item in items)
            {
                _items.Add(item);
            }
        }

        public void Dispose()
        {
        }

        public bool MoveNext()
        {
            _position++;
            return _position < _items.Count;
        }

        public void Reset()
        {
            _position = -1;
        }
    }
    public class MyList<T> : IEnumerable<T>
    {
        bool _updateUI = false;
        string _uiTag;
        public List<T> list;
        public MyList()
        {
            list = new List<T>();
        }
        public MyList(string tag)
        {
            list = new List<T>();
            _uiTag = tag;
            _updateUI = true;
        }
        public void Add(T item)
        {
            list.Add(item);
            UpdateUI();
        }
        public void RemoveAt(int index)
        {
            list.RemoveAt(index);
            UpdateUI();
        }
        public int Count
        {
            get
            {
                return list.Count;
            }
        }
        public void UpdateUI()
        {
            if (_updateUI)
            {
                AbstractFightInfoViewController.GetController().UpdateUI(_uiTag);
            }
        }
        public void Remove(T item)
        {
            list.Remove(item);
            UpdateUI();
        }
        public void Insert(int index, T item)
        {
            list.Insert(index, item);
            UpdateUI();
        }
        public bool Contains(T item)
        {
            return list.Contains(item);
        }
        public void Clear()
        {
            list.Clear();
            UpdateUI();
        }

        public IEnumerator<T> GetEnumerator()
        {
            return new MyListEnum<T>(list);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return new MyListEnum<T>(list);
        }

        public T this[int index]
        {
            get
            {
                return list[index];
            }
        }
    }
    /// <summary>
    /// 与牌相关的所有数据
    /// </summary>
    public interface ICardModel:IModel
    {
        /// <summary>
        /// 抽牌堆
        /// </summary>
        MyList<CardModelBase> drawPile { get; set; }
        /// <summary>
        /// 弃牌堆
        /// </summary>
        MyList<CardModelBase> discardPile { get; set; }
        /// <summary>
        /// 手牌
        /// </summary>
        MyList<CardControllerBase> hand { get; set; }

        /// <summary>
        /// 带入战斗中的牌库
        /// </summary>
        MyList<CardModelBase> cardLibrary { get; set; }

        /// <summary>
        /// 玩家所拥有的全部牌的牌库
        /// </summary>
        MyList<CardModelBase> playerCardLibrary { get; set; }

        /// <summary>
        /// 获取一张卡牌的默认数据
        /// </summary>
        /// <param name="card"></param>
        /// <returns></returns>
        AbstractCardModelBase GetCardModel(Card card);

        ICardFactory cardFactory { get; }

        /// <summary>
        /// 注册法力消耗函数
        /// </summary>
        /// <param name="ele"></param>
        /// <param name="decorator"></param>
        void RegisterManaCostDecorator(ElementType ele, IntDelegate decorator);
        void UnregisterManaCostDecorator(ElementType ele, IntDelegate decorator);

        /// <summary>
        /// 修饰法力消耗
        /// </summary>
        /// <param name="ori">原先数据</param>
        /// <param name="ele">元素种类</param>
        /// <returns></returns>
        int DecorateManaCost(int ori, ElementType ele);

    }
    public class CardModel : ICardModel
    {
        public CardModel()
        {
            LoadCards();
        }

        public MyList<CardModelBase> drawPile { get; set; } = new MyList<CardModelBase>("Draw");
        public MyList<CardModelBase> discardPile { get; set; } = new MyList<CardModelBase>("Discard");
        public MyList<CardControllerBase> hand { get; set; } = new MyList<CardControllerBase>("Hand");
        public MyList<CardModelBase> cardLibrary { get; set; } = new MyList<CardModelBase>();
        public MyList<CardModelBase> playerCardLibrary { get; set; } = new MyList<CardModelBase>();

        CardFactory _cardFactory = null;
        public ICardFactory cardFactory
        {
            get
            {
                if (_cardFactory == null)
                {
                    _cardFactory = new CardFactory();
                }
                return _cardFactory;
            }
        }

        /// <summary>
        /// 读取卡牌数据
        /// </summary>
        void LoadCards()
        {
            _cardModels = new Dictionary<Card, DefaultCardModel>();
            string path = Strings.GetString(StringType.CardDataPath);
            StreamReader reader = File.OpenText(path);
            List<DefaultCardModel> container;
            container = JsonUtility.FromJson<DefaultCardModels>(reader.ReadToEnd()).models;
            for (int i = 0; i < container.Count; i++)
            {
                DefaultCardModel content = container[i];
                Card card = (Card)Enum.Parse(typeof(Card), content.cardName);
                content.cardType = card;
                ElementType ele = (ElementType)Enum.Parse(typeof(ElementType), content.elementName);
                content.manaCost = content.ManaCost;
                content.description = content.Description;
                content.elementType = ele;
                _cardModels.Add(card, content);
            }
            ///读取玩家牌库
            LoadLibrary();
        }
        Dictionary<Card, DefaultCardModel> _cardModels;
        [Serializable]
        class DefaultCardModel : AbstractCardModelBase
        {
            public string cardName;
            public string elementName;
            public int ManaCost;
            public string Description;
        }
        [Serializable]
        class DefaultCardModels
        {
            public List<DefaultCardModel> models;
        }
        public AbstractCardModelBase GetCardModel(Card card)
        {
            if (_cardModels.ContainsKey(card))
            {
                return _cardModels[card];
            }
            return null;
        }
        /// <summary>
        /// 加载玩家牌库……本应如此，但测试中该函数内部可能会有一些奇奇怪怪的东西
        /// 不要太在意
        /// </summary>
        public void LoadLibrary()
        {
            cardLibrary.Add(new SampleCardModel(_cardModels[Card.Sample]));
            cardLibrary.Add(new SampleCardModel(_cardModels[Card.Sample]));
            cardLibrary.Add(new SampleCardModel(_cardModels[Card.Sample]));
            cardLibrary.Add(new SampleCardModel(_cardModels[Card.Sample]));
        }

        struct CardIdentifier
        {
            public ElementType ele;

            public CardIdentifier(ElementType elementType)
            {
                ele = elementType;
            }
        }

        Dictionary<CardIdentifier, IntDecorator> manaCostDecorator = new Dictionary<CardIdentifier, IntDecorator>();

        public void RegisterManaCostDecorator(ElementType ele, IntDelegate decorator)
        {
            CardIdentifier identifier = new CardIdentifier(ele);
            if (!manaCostDecorator.ContainsKey(identifier))
            {
                manaCostDecorator.Add(identifier, new IntDecorator());
            }
            manaCostDecorator[identifier].Register(decorator);
        }
        public void UnregisterManaCostDecorator(ElementType ele, IntDelegate decorator)
        {
            CardIdentifier identifier = new CardIdentifier(ele);
            if (manaCostDecorator.ContainsKey(identifier))
            {
                manaCostDecorator[identifier].Unregister(decorator);
            }
        }

        public int DecorateManaCost(int ori, ElementType ele)
        {
            CardIdentifier identifier = new CardIdentifier(ele);
            if (manaCostDecorator.ContainsKey(identifier))
            {
                return manaCostDecorator[identifier].Decorate(ori);
            }
            else
            {
                return ori;
            }
        }
    }
}
